﻿#include "Widget.h"
#include "ui_Widget.h"

#include <QDebug>
#include <QScrollBar>
#include <QMessageBox>
#include <QHostAddress>

#include "Screen.h"

#define OPEN_AUDIO "打开音频"
#define OPEN_VIDEO "打开视频"

QRect Widget::s_pos = QRect(-1, -1, -1, -1);

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    /*----------------UI界面-------------------*/
    m_isCreateMeeting = false;
    m_isOpenCamera = false;
    m_isJoinMeeting = false;

    m_mainWindowIp = 0;

    Widget::s_pos = QRect(0.1 * Screen::s_width, 0.1 * Screen::s_height, 0.8 * Screen::s_width, 0.8 * Screen::s_height);

    ui->m_btnOpenAudio->setText(QString(OPEN_AUDIO).toUtf8());
    ui->m_btnOpenAudio->setText(QString(OPEN_VIDEO).toUtf8());

    this->setGeometry(Widget::s_pos);
    this->setMinimumSize(QSize(Widget::s_pos.width() * 0.7, Widget::s_pos.height() * 0.7));
    this->setMaximumSize(QSize(Widget::s_pos.width(), Widget::s_pos.height()));

    ui->m_btnQuitMeeting->setDisabled(true);
    ui->m_btnJoinMeet->setDisabled(true);
    ui->m_btnCreatMeeting->setDisabled(true);
    ui->m_btnOpenAudio->setDisabled(true);
    ui->m_btnOpenVideo->setDisabled(true);
    ui->m_btnSendText->setDisabled(true);

    // 主屏幕显示的用户IP图像
    m_mainWindowIp = 0;

    /*----------------socket线程-------------------*/
    m_tcpSocket = new MyTcpSocket();    // 底部发送线程

    /*----------------音频-------------------*/
    m_sendAudioMsg = new SendAudioMsg();
    m_sendAudioThread = new QThread();
    m_sendAudioMsg->moveToThread(m_sendAudioThread);
    m_sendAudioThread->start();

    connect(this, &Widget::startAudioCollect, m_sendAudioMsg, &SendAudioMsg::onStartCollect);
    connect(m_sendAudioMsg, &SendAudioMsg::audioInputError, this, &Widget::onAudioError);

    m_loadAudio = new LoadAudio();
    m_loadAudio->start();

    connect(this, &Widget::stopAudioCollect, m_sendAudioMsg, &SendAudioMsg::onStopCollect);
    connect(m_loadAudio, &LoadAudio::audiooutputerror, this, &Widget::onAudioError);
    connect(m_loadAudio, &LoadAudio::speaker, this, &Widget::onSpeaks);

    /*----------------采集，发送视频-------------------*/

    /*------摄像头------*/
    m_camera = new QCamera(this);

    m_imageCapture = new QCameraImageCapture(m_camera);
    m_videoSurface = new MyVideoSurface(this);
    m_camera->setViewfinder(m_videoSurface);
    m_camera->setCaptureMode(QCamera::CaptureStillImage);

    connect(m_camera, SIGNAL(error(QCamera::Error)), this, SLOT(onCameraError(QCamera::Error)));
    connect(m_videoSurface, &MyVideoSurface::frameAvailable, this, &Widget::onCameraImageCapture);

    /*------视频发送------*/
    m_sendImgMsg = new SendImgMsg();
    m_sendImgThread = new QThread();
    m_sendImgMsg->moveToThread(m_sendImgThread);
    m_sendImgMsg->start();

    connect(this, &Widget::pushImg, m_sendImgMsg, &SendImgMsg::imageCapture);
    connect(m_sendImgThread, &QThread::finished, m_sendImgMsg, &SendImgMsg::clearImgQueue);

    /*----------------接收转发-------------------*/
    m_recvMsgTransmitter = new RecvMsgEmit();
    connect(m_recvMsgTransmitter, &RecvMsgEmit::recvMsg, this, &Widget::onSolveRecvMsg, Qt::BlockingQueuedConnection);
    m_recvMsgTransmitter->start();

    ui->scrollArea->verticalScrollBar()->setStyleSheet("QScrollBar:vertical { width:8px; background:rgba(0,0,0,0%); margin:0px,0px,0px,0px; padding-top:9px; padding-bottom:9px; } QScrollBar::handle:vertical { width:8px; background:rgba(0,0,0,25%); border-radius:4px; min-height:20; } QScrollBar::handle:vertical:hover { width:8px; background:rgba(0,0,0,50%); border-radius:4px; min-height:20; } QScrollBar::add-line:vertical { height:9px;width:8px; border-image:url(:/images/a/3.png); subcontrol-position:bottom; } QScrollBar::sub-line:vertical { height:9px;width:8px; border-image:url(:/images/a/1.png); subcontrol-position:top; } QScrollBar::add-line:vertical:hover { height:9px;width:8px; border-image:url(:/images/a/4.png); subcontrol-position:bottom; } QScrollBar::sub-line:vertical:hover { height:9px;width:8px; border-image:url(:/images/a/2.png); subcontrol-position:top; } QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical { background:rgba(0,0,0,10%); border-radius:4px; }");
    ui->listWidget->setStyleSheet("QScrollBar:vertical { width:8px; background:rgba(0,0,0,0%); margin:0px,0px,0px,0px; padding-top:9px; padding-bottom:9px; } QScrollBar::handle:vertical { width:8px; background:rgba(0,0,0,25%); border-radius:4px; min-height:20; } QScrollBar::handle:vertical:hover { width:8px; background:rgba(0,0,0,50%); border-radius:4px; min-height:20; } QScrollBar::add-line:vertical { height:9px;width:8px; border-image:url(:/images/a/3.png); subcontrol-position:bottom; } QScrollBar::sub-line:vertical { height:9px;width:8px; border-image:url(:/images/a/1.png); subcontrol-position:top; } QScrollBar::add-line:vertical:hover { height:9px;width:8px; border-image:url(:/images/a/4.png); subcontrol-position:bottom; } QScrollBar::sub-line:vertical:hover { height:9px;width:8px; border-image:url(:/images/a/2.png); subcontrol-position:top; } QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical { background:rgba(0,0,0,10%); border-radius:4px; }");

    QFont font = this->font();
    font.setFamily("MicrosoftYaHei");
    font.setPointSize(12);

    ui->listWidget->setFont(font);
    ui->tabWidget->setFont(font);

    ui->tabWidget->setCurrentIndex(0);
}

Widget::~Widget()
{
    if (m_sendAudioThread->isRunning()){
        m_sendAudioMsg->deleteLater();
        m_sendAudioThread->quit();
        m_sendAudioThread->wait();
        m_sendAudioThread->deleteLater();
    }

    if(m_tcpSocket->isRunning()){
        m_tcpSocket->StopTcpThread();
        m_tcpSocket->wait();
        m_tcpSocket->deleteLater();
    }

    if (m_recvMsgTransmitter->isRunning()){
        m_recvMsgTransmitter->stopRecvSolveThread();
        m_recvMsgTransmitter->wait();
        m_recvMsgTransmitter->deleteLater();
    }

    if (m_loadAudio->isRunning()){
        m_loadAudio->stopImmediately();
        m_loadAudio->wait();
        m_loadAudio->deleteLater();
    }

    delete ui;
}

void Widget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
}

void Widget::on_m_btnCreatMeeting_clicked()
{
    m_sendComMsg.toSendQueue(MsgType::MsgType_CreatMeeting);

    ui->m_btnOpenAudio->setDisabled(false);
    ui->m_btnOpenVideo->setDisabled(false);
    ui->m_btnCreatMeeting->setDisabled(true);
    ui->m_btnJoinMeet->setDisabled(true);
    ui->m_btnQuitMeeting->setDisabled(false);
}

void Widget::on_m_btnQuitMeeting_clicked()
{
    m_sendComMsg.toSendQueue(MsgType::MsgType_ExitMeeting);

    if (m_camera->state() == QCamera::ActiveState) {
        m_camera->stop();
    }

    ui->m_btnCreatMeeting->setDisabled(true);
    ui->m_btnQuitMeeting->setDisabled(true);
    m_isCreateMeeting = false;
    m_isJoinMeeting = false;

    clearPartner();

    m_tcpSocket->disconnectFromHost();
    m_tcpSocket->wait();

    ui->m_labOutLog->setText("已退出会议");

    ui->m_btnConnectSever->setEnabled(true);

    // while (ui->listWidget->count() > 0) {
    //     QListWidget *item = ui->listWidget->takeItem(0);
    //     delete item;
    // }
    m_lstIp.clear();

    QMessageBox::warning(this, "Information", "退出会议" , QMessageBox::Yes, QMessageBox::Yes);
}

void Widget::on_m_btnJoinMeet_clicked()
{
    QString roomNo = ui->m_ldtMeetNo->text();

    QRegExp roomReg("^[1-9][0-9]{1,5}$");
    QRegExpValidator roomValidate(roomReg);
    int pos = 0;
    if (roomValidate.validate(roomNo, pos) != QValidator::Acceptable) {
        QMessageBox::warning(this, "RoomNo Error", "房间号不合法", QMessageBox::Yes, QMessageBox::Yes);
    } else {
        quint32 tmp = roomNo.toUInt();
        LOG << tmp;
        m_sendComMsg.toSendJoinMsgQueue(MsgType_JoinMeeting, tmp);
    }
}

void Widget::on_m_btnSendText_clicked()
{
    QByteArray data = qCompress(QByteArray::fromStdString(ui->m_tdtSendText->toPlainText().toStdString()));
    m_sendComMsg.toSendQueue(MsgType::MsgType_TextSend, data);
}

void Widget::on_m_btnConnectSever_clicked()
{
    // m_tcpSocket->start();
    ui->m_labOutLog->setText("正在连接服务器");

    if (m_tcpSocket->connectToServer()) {
        ui->m_labOutLog->setText("成功连接服务器");

        ui->m_btnOpenAudio->setDisabled(true);
        ui->m_btnOpenVideo->setDisabled(true);

        ui->m_btnCreatMeeting->setEnabled(true);
        ui->m_btnJoinMeet->setEnabled(true);
        ui->m_btnQuitMeeting->setDisabled(true);

        QMessageBox::warning(this, "Connection success", "成功连接服务器" , QMessageBox::Yes, QMessageBox::Yes);
    } else {
        ui->m_labOutLog->setText("连接失败，请过一段时间重试");
        QMessageBox::warning(this, "Connection error", m_tcpSocket->errorString() , QMessageBox::Yes, QMessageBox::Yes);
    }
}

void Widget::onSolveRecvMsg(MESG *msg)
{
    LOG << "onSolveRecvMsg";
    if (msg->type == MsgType_CreatMeetingResponse) {
        int roomNo;
        memcpy(&roomNo, msg->data.get(), msg->size);
        ui->m_ldtMeetNo->setText(QString("会议号:%1").arg(roomNo));

        if (roomNo != 0) {
            QMessageBox::information(this, "Room No", QString("房间号：%1").arg(roomNo),
                                     QMessageBox::Yes, QMessageBox::Yes);

            ui->m_labOutLog->setText(QString("创建成功 房间号: %1").arg(roomNo));
            m_isCreateMeeting = true;

            ui->m_btnJoinMeet->setDisabled(true);
            ui->m_btnQuitMeeting->setDisabled(false);

            ui->m_btnOpenAudio->setDisabled(false);
            ui->m_btnOpenVideo->setDisabled(false);

            addPartner(m_tcpSocket->getLocalIp());
            m_mainWindowIp = m_tcpSocket->getLocalIp();

            QImage defaultImage = QImage(":/myImage/1.jpg").scaled(ui->m_mainShowLabel->size());
            ui->m_mainShowLabel->setPixmap(QPixmap::fromImage(defaultImage));

        } else {
            m_isCreateMeeting = false;
            QMessageBox::information(this, "Room Information", QString("无可用房间"),
                                     QMessageBox::Yes, QMessageBox::Yes);
            ui->m_labOutLog->setText(QString("无可用房间"));
            ui->m_btnCreatMeeting->setDisabled(false);
        }
    } else if (msg->type == MsgType_JoinMeetingResponse){
        qint32 roomStatus;
        memcpy(&roomStatus, (char *)msg->data.get(), msg->size);
        switch (roomStatus) {
        case 0:
            QMessageBox::information(this, "Meeting Error", tr("会议不存在"),
                                     QMessageBox::Yes, QMessageBox::Yes);
            ui->m_labOutLog->setText("会议不存在");

            ui->m_btnJoinMeet->setEnabled(true);

            ui->m_btnConnectSever->setDisabled(true);
            ui->m_btnQuitMeeting->setDisabled(true);
            ui->m_btnOpenAudio->setDisabled(true);
            ui->m_btnOpenVideo->setDisabled(true);
            break;
        case -1:
            QMessageBox::information(this, "Meeting information", tr("成员已满，无法加入"),
                                     QMessageBox::Yes, QMessageBox::Yes);
            ui->m_labOutLog->setText("成员已满，无法加入");
            break;
        default:
            QMessageBox::information(this, "Meeting information", tr("加入成功"),
                                     QMessageBox::Yes, QMessageBox::Yes);
            ui->m_labOutLog->setText("加入成功");

            addPartner(m_tcpSocket->getLocalIp());
            m_mainWindowIp = m_tcpSocket->getLocalIp();
            ui->groupBox_5->setTitle(QHostAddress(m_mainWindowIp).toString());
            QImage defaultImage = QImage(":/myImage/1.jpg").scaled(ui->m_mainShowLabel->size());
            ui->m_mainShowLabel->setPixmap(QPixmap::fromImage(defaultImage));

            ui->m_btnJoinMeet->setDisabled(true);
            ui->m_btnQuitMeeting->setEnabled(true);
            ui->m_btnCreatMeeting->setDisabled(true);
            m_isJoinMeeting = true;
            break;
        }
    } else if (msg->type == MsgType_ImgRecv) {
        QHostAddress a(msg->ip);
        LOG << "ImgRecv ip " << a.toString();
        QImage img;
        img.loadFromData(msg->data.get(), msg->size);
        Partner *tmp = nullptr;
        if (m_roomPartners.count(msg->ip) == 1) {
            tmp = m_roomPartners[msg->ip];
        } else {
            tmp = addPartner(msg->ip);
        }
        tmp->setPic(img);

        if (msg->ip == m_mainWindowIp) {
            auto mainShowPix = QPixmap::fromImage(img).scaled(ui->m_mainShowLabel->size());
            ui->m_mainShowLabel->setPixmap(mainShowPix);
        }
        repaint();
    } else if (msg->type == MsgType_PartnerJoin){
        Partner * p = addPartner(msg->ip);
        if (p) {
            p->setPic(QImage(":/myImage/1.jpg"));
            ui->m_labOutLog->setText(QString("%1 join meeting").arg(QHostAddress(msg->ip).toString()));
            m_lstIp.append(QString("@") + QHostAddress(msg->ip).toString());
            // plainTextEdit
        }
    } else if (msg->type == MsgType_PartnerJoin2) {         // 批量加入会议
        uint32_t ip;
        int other = msg->size / sizeof(uint32_t), pos = 0;
        for (int i = 0; i < other; ++i) {
            memcpy_s(&ip, sizeof(uint32_t), msg->data.get() + pos, sizeof(uint32_t));
            pos += sizeof(uint32_t);
            Partner *p = addPartner(ip);
            if (p) {
                p->setPic(QImage(":/myImage/1.jpg"));
                m_lstIp << QString("@") + QHostAddress(ip).toString();
            }
        }
        ui->m_btnOpenVideo->setEnabled(true);
    } else if (msg->type == MsgType_CloseCamera) {
        closeImg(msg->ip);
    } else if (msg->type == MsgType_PartnerExit) {
        removePartner(msg->ip);

        if (m_mainWindowIp == msg->ip) {
            QImage defaultImage = QImage(":/myImage/1.jpg").scaled(ui->m_mainShowLabel->size());
            ui->m_mainShowLabel->setPixmap(QPixmap::fromImage(defaultImage));
        }

        if (m_lstIp.removeOne(QString("@") + QHostAddress(msg->ip).toString())) {

        } else {
            LOG <<  QHostAddress(msg->ip).toString() << "not exist";
        }

        ui->m_labOutLog->setText(QString("%1 exit meeting").arg(QHostAddress(msg->ip).toString()));
    }

    if (nullptr != msg) {
        delete msg;
        msg = nullptr;
    }
}

// 响应副屏幕点击，将点击的副屏幕设置主屏幕
void Widget::onRecvIp(quint32 ip)
{
    if (m_roomPartners.contains(m_mainWindowIp)) {
        Partner *p = m_roomPartners[m_mainWindowIp];
        p->setStyleSheet("border-width: 1px; border-style: solid; border-color:rgba(0, 0 , 255, 0.7)");
    }

    if (m_roomPartners.contains(ip)) {
        Partner *p = m_roomPartners[ip];
        p->setStyleSheet("border-width: 1px; border-style: solid; border-color:rgba(255, 0 , 0, 0.7)");
    }

    QImage defaultImage = QImage(":/myImage/1.jpg").scaled(ui->m_mainShowLabel->size());
    ui->m_mainShowLabel->setPixmap(QPixmap::fromImage(defaultImage));
    m_mainWindowIp = ip;
}

void Widget::onCameraError(QCamera::Error)
{
    QMessageBox::warning(this, "Camera error", m_camera->errorString() , QMessageBox::Yes, QMessageBox::Yes);
}

void Widget::onCameraImageCapture(QVideoFrame frame)
{
    if (frame.isValid() && frame.isReadable()) {
        QImage videoImg = QImage(frame.bits(), frame.width(), frame.height(),
                                 QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat()));
        QTransform matrix;
        matrix.rotate(180.0);

        QImage img = videoImg.transformed(matrix, Qt::FastTransformation).scaled(ui->m_mainShowLabel->size());

        if (m_roomPartners.size() > 1) {
            emit pushImg(img);
        }

        if (m_tcpSocket->getLocalIp() == m_mainWindowIp) {
            ui->m_mainShowLabel->setPixmap(QPixmap::fromImage(img).scaled(ui->m_mainShowLabel->size()));
        }

        Partner *p = m_roomPartners[m_tcpSocket->getLocalIp()];
        if (nullptr != p) {
            p->setPic(img);
        }
    }

    frame.unmap();
}

void Widget::onAudioError(QString errorStr)
{
    QMessageBox::warning(this, "Audio error", errorStr, QMessageBox::Yes);
}

void Widget::onSpeaks(QString ip)
{
    ui->m_labOutLog->setText(QString(ip + "正在说话").toUtf8());
}

void Widget::on_m_btnOpenAudio_clicked(bool checked)
{
    if (!m_isCreateMeeting && !m_isJoinMeeting) {
        return ;
    }
    if (checked == true) {
        ui->m_btnOpenAudio->setText("关闭音频");
        emit startAudioCollect();
    } else {
        ui->m_btnOpenAudio->setText("关闭音频");
        emit stopAudioCollect();
    }
}

void Widget::on_m_btnOpenVideo_clicked()
{
    if (m_camera->status() == QCamera::ActiveState) {
        m_camera->stop();
        if (m_camera->error() == QCamera::NoError) {
            m_sendImgThread->quit();
            m_sendImgThread->wait();
            ui->m_btnOpenVideo->setText("开启摄像头");
            m_sendComMsg.toSendQueue(MsgType_CloseCamera);
        }
        closeImg(m_tcpSocket->getLocalIp());
    } else {
        m_camera->start();
        LOG << "open Camera";
        if (m_camera->error() == QCamera::NoError) {
            m_sendImgThread->start();
            ui->m_btnOpenVideo->setText("关闭摄像头");
        }
    }
}

// 关闭一个ip的视频传输，将其设置为默认照片
void Widget::closeImg(quint32 ip)
{
    if (!m_roomPartners.contains(ip)) {
        LOG << "close img error";
        return;
    }
    Partner *p = m_roomPartners[ip];
    p->setPic(QImage(":/myImage/1.jpg"));

    if (m_mainWindowIp == ip) {

        ui->m_mainShowLabel->setPixmap(QPixmap::fromImage(QImage("./myImage/1.jpg").scaled(ui->m_mainShowLabel->size())));
    }
}

Partner *Widget::addPartner(quint32 ip)
{
    if (m_roomPartners.contains(ip)) {return nullptr;}

    Partner *p = new Partner(ui->scrollAreaWidgetContents, ip);
    if (nullptr == p) {
        return nullptr;
    }

    connect(p, &Partner::sendIp, this, &Widget::onRecvIp);
    m_roomPartners.insert(ip, p);
    ui->verticalLayout_6->addWidget(p, 1);

    if (m_roomPartners.size() > 1) {
        connect(this, &Widget::volumnChange, m_sendAudioMsg, &SendAudioMsg::setVolumn, Qt::UniqueConnection);
        connect(this, &Widget::volumnChange, m_loadAudio, &LoadAudio::onSetVolumn, Qt::UniqueConnection);

        ui->m_btnOpenAudio->setDisabled(false);
        m_loadAudio->startPlay();
    }

    return p;
}

void Widget::removePartner(quint32 ip)
{
    if (!m_roomPartners.contains(ip)) {
        return;
    }
    Partner *p = m_roomPartners[ip];
    disconnect(p, &Partner::sendIp, this, &Widget::onRecvIp);
    ui->verticalLayout_6->removeWidget(p);
    delete p;
    m_roomPartners.remove(ip);

    //只有自已一个人时，关闭传输音频
    if (m_roomPartners.size() <= 1) {
        disconnect(m_sendAudioMsg, SLOT(onSetVolumn(int)));
        disconnect(m_loadAudio, SLOT(onSetVolumn(int)));
        m_sendAudioMsg->onStopCollect();
        m_loadAudio->stopPlay();
        ui->m_btnOpenAudio->setText("打开音频");
        ui->m_btnOpenAudio->setDisabled(true);
    }
}

void Widget::clearPartner()
{
    ui->m_mainShowLabel->setPixmap(QPixmap());
    if (m_roomPartners.size() == 0) return;

    auto iter = m_roomPartners.begin();
    while (iter != m_roomPartners.end()) {
        quint32 ip = iter.key();
        iter++;
        Partner *p = m_roomPartners.take(ip);
        ui->verticalLayout_6->removeWidget(p);
        delete p;
        p = nullptr;
    }

    disconnect(m_sendAudioMsg, SLOT(onSetVolumn(int)));
    disconnect(m_loadAudio, SLOT(onSetVolumn(int)));

    m_sendAudioMsg->onStopCollect();
    m_loadAudio->stopPlay();
    ui->m_btnOpenAudio->setText("开启音频");
    ui->m_btnOpenAudio->setEnabled(true);

    if (m_sendImgThread->isRunning()) {
        m_sendImgThread->quit();
        m_sendImgThread->wait();
    }
    ui->m_btnOpenAudio->setText("开启视频");
    ui->m_btnOpenAudio->setEnabled(true);

}

void Widget::on_m_hsdrSetVolume_valueChanged(int value)
{
    emit volumnChange(value);
}

